home *** CD-ROM | disk | FTP | other *** search
- /* tc-sh.c -- Assemble code for the Hitachi Super-H
-
- Copyright (C) 1993 Free Software Foundation.
-
- This file is part of GAS, the GNU Assembler.
-
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /*
- Written By Steve Chamberlain
- sac@cygnus.com
- */
-
- #include <stdio.h>
- #include "as.h"
- #include "bfd.h"
- #include "subsegs.h"
- #define DEFINE_TABLE
- #include "../opcodes/sh-opc.h"
- #include <ctype.h>
-
- const char comment_chars[] = "!";
- const char line_separator_chars[] = ";";
- const char line_comment_chars[] = "!";
-
- /* This table describes all the machine specific pseudo-ops the assembler
- has to support. The fields are:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function
- */
-
- void cons ();
- void s_align_bytes();
-
- const pseudo_typeS md_pseudo_table[] =
- {
- {"int", cons, 4},
- {"data.b", cons, 1},
- {"data.w", cons, 2},
- {"data.l", cons, 4},
- {"form", listing_psize, 0},
- {"heading", listing_title, 0},
- {"import", s_ignore, 0},
- {"page", listing_eject, 0},
- {"program", s_ignore, 0},
- /* {"align", s_align_bytes, 0},*/
- {0, 0, 0}
- };
-
- /*int md_reloc_size;*/
-
- static int relax; /* set if -relax seen */
-
- const char EXP_CHARS[] = "eE";
-
- /* Chars that mean this number is a floating point constant */
- /* As in 0f12.456 */
- /* or 0d1.2345e12 */
- const char FLT_CHARS[] = "rRsSfFdDxXpP";
-
- #define C(a,b) ENCODE_RELAX(a,b)
-
- #define JREG 14 /* Register used as a temp when relaxing */
- #define ENCODE_RELAX(what,length) (((what) << 4) + (length))
- #define GET_WHAT(x) ((x>>4))
-
- /* These are the two types of relaxable instrction */
- #define COND_JUMP 1
- #define UNCOND_JUMP 2
-
- #define UNDEF_DISP 0
- #define COND8 1
- #define COND12 2
- #define COND32 3
- #define UNCOND12 1
- #define UNCOND32 2
- #define UNDEF_WORD_DISP 4
- #define END 5
-
- #define UNCOND12 1
- #define UNCOND32 2
-
- #define COND8_F 254
- #define COND8_M -256
- #define COND8_LENGTH 2
- #define COND12_F (4094 - 4) /* -4 since there are two extra */
- /* instructions needed */
- #define COND12_M -4096
- #define COND12_LENGTH 6
- #define COND32_F (1<<30)
- #define COND32_M -(1<<30)
- #define COND32_LENGTH 14
-
- #define UNCOND12_F 4094
- #define UNCOND12_M -4096
- #define UNCOND12_LENGTH 2
-
- #define UNCOND32_F (1<<30)
- #define UNCOND32_M -(1<<30)
- #define UNCOND32_LENGTH 14
-
-
- relax_typeS md_relax_table[C (END, 0)];
-
- static struct hash_control *opcode_hash_control; /* Opcode mnemonics */
-
- /*
- This function is called once, at assembler startup time. This should
- set up all the tables, etc that the MD part of the assembler needs
- */
-
- void
- md_begin ()
- {
- sh_opcode_info *opcode;
- char *prev_name = "";
-
- opcode_hash_control = hash_new ();
-
- /* Insert unique names into hash table */
- for (opcode = sh_table; opcode->name; opcode++)
- {
- if (strcmp (prev_name, opcode->name))
- {
- prev_name = opcode->name;
- hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
- }
- else {
- /* Make all the opcodes with the same name point to the same
- string */
- opcode->name = prev_name;
- }
- }
-
- /* Initialize the relax table */
- md_relax_table[C (COND_JUMP, COND8)].rlx_forward = COND8_F;
- md_relax_table[C (COND_JUMP, COND8)].rlx_backward = COND8_M;
- md_relax_table[C (COND_JUMP, COND8)].rlx_length = COND8_LENGTH;
- md_relax_table[C (COND_JUMP, COND8)].rlx_more = C (COND_JUMP, COND12);
-
- md_relax_table[C (COND_JUMP, COND12)].rlx_forward = COND12_F;
- md_relax_table[C (COND_JUMP, COND12)].rlx_backward = COND12_M;
- md_relax_table[C (COND_JUMP, COND12)].rlx_length = COND12_LENGTH;
- md_relax_table[C (COND_JUMP, COND12)].rlx_more = C (COND_JUMP, COND32);
-
- md_relax_table[C (COND_JUMP, COND32)].rlx_forward = COND32_F;
- md_relax_table[C (COND_JUMP, COND32)].rlx_backward = COND32_M;
- md_relax_table[C (COND_JUMP, COND32)].rlx_length = COND32_LENGTH;
- md_relax_table[C (COND_JUMP, COND32)].rlx_more = 0;
-
-
- md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_forward = UNCOND12_F;
- md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_backward = UNCOND12_M;
- md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length = UNCOND12_LENGTH;
- md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_more = C (UNCOND_JUMP, UNCOND32);
-
- md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_forward = UNCOND32_F;
- md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_backward = UNCOND32_M;
- md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length = UNCOND32_LENGTH;
- md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_more = 0;
-
-
- }
-
- static int reg_m;
- static int reg_n;
- static expressionS immediate; /* absolute expression */
-
- typedef struct
- {
- sh_arg_type type;
- int reg;
- }
-
- sh_operand_info;
-
- /* try and parse a reg name, returns number of chars consumed */
- static int
- parse_reg (src, mode, reg)
- char *src;
- int *mode;
- int *reg;
- {
- if (src[0] == 'r')
- {
- if (src[1] == '1')
- {
- if (src[2] >= '0' && src[2] <= '5')
- {
- *mode = A_REG_N;
- *reg = 10 + src[2] - '0';
- return 3;
- }
- }
- if (src[1] >= '0' && src[1] <= '9')
- {
- *mode = A_REG_N;
- *reg = (src[1] - '0');
- return 2;
- }
- }
-
- if (src[0] == 's' && src[1] == 'r')
- {
- *mode = A_SR;
- return 2;
- }
-
- if (src[0] == 's' && src[1] == 'p')
- {
- *mode = A_REG_N;
- *reg = 15;
- return 2;
- }
-
- if (src[0] == 'p' && src[1] == 'r')
- {
- *mode = A_PR;
- return 2;
- }
- if (src[0] == 'p' && src[1] == 'c')
- {
- *mode = A_DISP_PC;
- return 2;
- }
- if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r')
- {
- *mode = A_GBR;
- return 3;
- }
- if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r')
- {
- *mode = A_VBR;
- return 3;
- }
-
- if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c')
- {
- if (src[3] == 'l')
- {
- *mode = A_MACL;
- return 4;
- }
- if (src[3] == 'h')
- {
- *mode = A_MACH;
- return 4;
- }
- }
-
-
- return 0;
- }
-
- static
- char *
- parse_exp (s)
- char *s;
- {
- char *save;
- char *new;
- segT seg;
-
- save = input_line_pointer;
-
-
- input_line_pointer = s;
-
- seg = expr (0, &immediate);
- new = input_line_pointer;
- input_line_pointer = save;
- if (SEG_NORMAL (seg))
- return new;
- switch (seg)
- {
- case SEG_ABSOLUTE:
- case SEG_UNKNOWN:
- case SEG_DIFFERENCE:
- case SEG_BIG:
- case SEG_REGISTER:
- return new;
- case SEG_ABSENT:
- as_bad ("Missing operand");
- return new;
- default:
- as_bad ("Don't understand operand of type %s", segment_name (seg));
- return new;
- }
- }
-
-
- /* The many forms of operand:
-
- Rn Register direct
- @Rn Register indirect
- @Rn+ Autoincrement
- @-Rn Autodecrement
- @(disp:4,Rn)
- @(disp:8,GBR)
- @(disp:8,PC)
-
- @(R0,Rn)
- @(R0,GBR)
-
- disp:8
- disp:12
- #imm8
- pr, gbr, vbr, macl, mach
-
- */
-
- static
- char *parse_at(src, op)
- char *src;
- sh_operand_info *op;
- {
- int len;
- int mode;
- src++;
- if (src[0] == '-')
- {
- /* Must be predecrement */
- src++;
-
- len = parse_reg (src, &mode, &(op->reg));
- if (mode != A_REG_N)
- as_bad ("illegal register after @-");
-
- op->type = A_DEC_N;
- src += len;
- }
- else if (src[0] == '(')
- {
- /* Could be @(disp, rn), @(disp, gbr), @(disp, pc), @(r0, gbr) or
- @(r0, rn) */
- src++;
- len = parse_reg (src, &mode, &(op->reg));
- if (len && mode == A_REG_N)
- {
- src += len;
- if (op->reg != 0)
- {
- as_bad ("must be @(r0,...)");
- }
- if (src[0] == ',')
- src++;
- /* Now can be rn or gbr */
- len = parse_reg (src, &mode, &(op->reg));
- if (mode == A_GBR)
- {
- op->type = A_R0_GBR;
- }
- else if (mode == A_REG_N)
- {
- op->type = A_IND_R0_REG_N;
- }
- else
- {
- as_bad ("syntax error in @(r0,...)");
- }
- }
- else
- {
- /* Must be an @(disp,.. thing) */
- src = parse_exp (src);
- if (src[0] == ',')
- src++;
- /* Now can be rn, gbr or pc */
- len = parse_reg (src, &mode, &op->reg);
- if (len)
- {
- if (mode == A_REG_N)
- {
- op->type = A_DISP_REG_N;
- }
- else if (mode == A_GBR)
- {
- op->type = A_DISP_GBR;
- }
- else if (mode == A_DISP_PC)
- {
- op->type = A_DISP_PC;
- }
- else
- {
- as_bad ("syntax error in @(disp,[Rn, gbr, pc])");
- }
- }
- else
- {
- as_bad ("syntax error in @(disp,[Rn, gbr, pc])");
- }
- }
- src += len;
- if (src[0] != ')')
- as_bad("expecting )");
- else
- src ++;
- }
- else
- {
- src += parse_reg (src, &mode, &(op->reg));
- if (mode != A_REG_N)
- {
- as_bad ("illegal register after @");
- }
- if (src[0] == '+')
- {
- op->type = A_INC_N;
- src++;
- }
- else
- {
- op->type = A_IND_N;
- }
- }
- return src;
- }
-
- static void
- get_operand (ptr, op)
- char **ptr;
- sh_operand_info *op;
- {
- char *src = *ptr;
- int mode = -1;
- unsigned int len;
-
- if (src[0] == '#')
- {
- src++;
- *ptr = parse_exp (src);
- op->type = A_IMM;
- return;
- }
-
- else if (src[0] == '@')
- {
- *ptr = parse_at(src, op);
- return;
- }
- len = parse_reg (src, &mode, &(op->reg));
- if (len)
- {
- *ptr = src + len;
- op->type = mode;
- return;
- }
- else
- {
- /* Not a reg, the only thing left is a displacement */
- *ptr = parse_exp(src);
- op->type = A_DISP_PC;
- return;
- }
- }
-
- static
- char *
- get_operands (info, args, operand)
- sh_opcode_info *info;
- char *args;
- sh_operand_info *operand;
-
- {
- char *ptr = args;
- if (info->arg[0])
- {
- ptr++;
-
- get_operand (&ptr, operand + 0);
- if (info->arg[1])
- {
- if (*ptr == ',')
- {
- ptr++;
- }
- get_operand (&ptr, operand + 1);
- }
- else
- {
- operand[1].type = 0;
- }
- }
- else
- {
- operand[0].type = 0;
- operand[1].type = 0;
- }
- return ptr;
- }
-
- /* Passed a pointer to a list of opcodes which use different
- addressing modes, return the opcode which matches the opcodes
- provided
- */
-
- static
- sh_opcode_info *
- get_specific (opcode, operands)
- sh_opcode_info *opcode;
- sh_operand_info *operands;
- {
- sh_opcode_info *this_try = opcode;
- char *name = opcode->name;
- int arg_to_test = 0;
- int n = 0;
- while (opcode->name)
- {
- this_try = opcode++;
- if (this_try->name != name)
- {
- /* We've looked so far down the table that we've run out of
- opcodes with the same name */
- return 0;
- }
- /* look at both operands needed by the opcodes and provided by
- the user - since an arg test will often fail on the same arg
- again and again, we'll try and test the last failing arg the
- first on each opcode try */
-
- for (n = 0; this_try->arg[n]; n++)
- {
- sh_operand_info *user = operands + arg_to_test;
- sh_arg_type arg = this_try->arg[arg_to_test];
- switch (arg)
- {
- case A_IMM:
- case A_BDISP12:
- case A_BDISP8:
- case A_DISP_GBR:
- case A_DISP_PC:
- case A_MACH:
- case A_PR:
- case A_MACL:
- if (user->type != arg) goto fail;
- break;
- case A_R0:
- /* opcode needs r0 */
- if (user->type != A_REG_N || user->reg != 0) goto fail;
- break;
- case A_REG_N:
- case A_INC_N:
- case A_DEC_N:
- case A_IND_N:
- case A_IND_R0_REG_N:
- case A_DISP_REG_N:
- /* Opcode needs rn */
- if (user->type != arg) goto fail;
- reg_n = user->reg;
- break;
-
- case A_REG_M:
- case A_INC_M:
- case A_DEC_M:
- case A_IND_M:
- case A_IND_R0_REG_M:
- case A_DISP_REG_M:
- /* Opcode needs rn */
- if (user->type != arg - A_REG_M + A_REG_N) goto fail;
- reg_m = user->reg;
- break;
- default:
- printf ("unhandled %d\n", arg);
- goto fail;
- }
- /* If we did 0, test 1 next, else 0 */
- arg_to_test = 1 - arg_to_test;
- }
- return this_try;
- fail:;
- }
-
- return 0;
- }
-
- int
- check (operand, low, high)
- expressionS *operand;
- int low;
- int high;
- {
- if (operand->X_seg != SEG_ABSOLUTE
- || operand->X_add_number < low
- || operand->X_add_number > high)
- {
- as_bad ("operand must be absolute in range %d..%d", low, high);
- }
- return operand->X_add_number;
- }
-
-
- static void
- insert (where, how, pcrel)
- char *where;
- int how;
- int pcrel;
- {
- fix_new (frag_now,
- where - frag_now->fr_literal,
- 4,
- immediate.X_add_symbol,
- immediate.X_subtract_symbol,
- immediate.X_add_number,
- pcrel,
- how);
-
- }
-
- static void
- build_relax (opcode)
- sh_opcode_info *opcode;
- {
- int len;
- char *p;
- if (opcode->arg[0] == A_BDISP8)
- {
- p = frag_var(rs_machine_dependent,
- md_relax_table[C(COND_JUMP, COND32)].rlx_length,
- len = md_relax_table[C(COND_JUMP, COND8)].rlx_length,
- C(COND_JUMP, 0),
- immediate.X_add_symbol,
- immediate.X_add_number,
- 0);
- p[0] = (opcode->nibbles[0] << 4) | (opcode->nibbles[1]);
- }
- else if (opcode->arg[0] == A_BDISP12)
- {
- p = frag_var(rs_machine_dependent,
- md_relax_table[C(UNCOND_JUMP, UNCOND32)].rlx_length,
- len = md_relax_table[C(UNCOND_JUMP, UNCOND12)].rlx_length,
- C(UNCOND_JUMP, 0),
- immediate.X_add_symbol,
- immediate.X_add_number,
- 0);
- p[0] = (opcode->nibbles[0] << 4) ;
- }
-
- }
- /* Now we know what sort of opcodes it is, lets build the bytes -
- */
- static void
- build_Mytes (opcode, operand)
- sh_opcode_info *opcode;
- sh_operand_info *operand;
-
- {
- int index;
- char nbuf[4];
- char *output = frag_more (2);
-
- nbuf[0] = 0;
- nbuf[1] = 0;
- nbuf[2] = 0;
- nbuf[3] = 0;
-
- for (index = 0; index < 4; index++)
- {
- sh_nibble_type i = opcode->nibbles[index];
- if (i < 16)
- {
- nbuf[index] = i;
- }
- else
- {
- switch (i)
- {
- case REG_N:
- nbuf[index] = reg_n;
- break;
- case REG_M:
- nbuf[index] = reg_m;
- break;
- case DISP_4:
- insert(output + 1, R_SH_IMM4,0);
- break;
- case IMM_4BY4:
- insert(output + 1, R_SH_IMM4BY4,0);
- break;
- case IMM_4BY2:
- insert(output + 1, R_SH_IMM4BY2,0);
- break;
- case IMM_4:
- insert(output + 1, R_SH_IMM4,0);
- break;
- case IMM_8BY4:
- insert(output + 1, R_SH_IMM8BY4,0);
- break;
- case IMM_8BY2:
- insert(output + 1, R_SH_IMM8BY2,0);
- break;
- case IMM_8:
- insert(output + 1, R_SH_IMM8,0);
- break;
- case PCRELIMM_8BY4:
- insert(output + 1, R_SH_PCRELIMM8BY4,0);
- break;
- case PCRELIMM_8BY2:
- insert(output + 1, R_SH_PCRELIMM8BY2,0);
- break;
- default:
- printf ("failed for %d\n", i);
- }
- }
- }
- output[0] = (nbuf[0] << 4) | (nbuf[1]);
- output[1] = (nbuf[2] << 4) | (nbuf[3]);
- }
-
- /* This is the guts of the machine-dependent assembler. STR points to a
- machine dependent instruction. This function is supposed to emit
- the frags/bytes it assembles to.
- */
-
- void
- md_assemble(str)
- char *str;
- {
- unsigned char *op_start;
- unsigned char *op_end;
- sh_operand_info operand[2];
- sh_opcode_info *opcode;
- unsigned char *name;
-
- int nlen = 0;
-
- /* Drop leading whitespace */
- while (*str == ' ')
- str++;
-
- /* find the op code end */
- for (name = op_start = op_end = (unsigned char *)(str);
- *op_end &&
- !is_end_of_line[*op_end] && *op_end != ' ';
- op_end++)
- {
- nlen++;
- }
- name[nlen] = 0;
-
- if (op_end == op_start)
- {
- as_bad ("can't find opcode ");
- }
-
- opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name);
-
- if (opcode == NULL)
- {
- as_bad ("unknown opcode");
- return;
- }
-
- if (opcode->arg[0] == A_BDISP12
- || opcode->arg[0] == A_BDISP8)
- {
- input_line_pointer = parse_exp(op_end + 1);
- build_relax(opcode);
- }
- else
- {
- input_line_pointer = get_operands (opcode, op_end, operand);
-
- opcode = get_specific (opcode, operand);
-
- if (opcode == 0)
- {
- /* Couldn't find an opcode which matched the operands */
- char *where = frag_more (2);
-
- where[0] = 0x0;
- where[1] = 0x0;
- as_bad ("invalid operands for opcode");
- return;
- }
-
- build_Mytes (opcode, operand);
- }
-
- }
-
- void
- DEFUN (tc_crawl_symbol_chain, (headers),
- object_headers * headers)
- {
- printf ("call to tc_crawl_symbol_chain \n");
- }
-
- symbolS *
- DEFUN (md_undefined_symbol, (name),
- char *name)
- {
- return 0;
- }
-
- void
- DEFUN (tc_headers_hook, (headers),
- object_headers * headers)
- {
- printf ("call to tc_headers_hook \n");
- }
-
- void
- DEFUN_VOID (md_end)
- {
- }
-
- /* Various routines to kill one day */
- /* Equal to MAX_PRECISION in atof-ieee.c */
- #define MAX_LITTLENUMS 6
-
- /* Turn a string in input_line_pointer into a floating point constant of type
- type, and store the appropriate bytes in *litP. The number of LITTLENUMS
- emitted is stored in *sizeP . An error message is returned, or NULL on OK.
- */
- char *
- md_atof (type, litP, sizeP)
- char type;
- char *litP;
- int *sizeP;
- {
- int prec;
- LITTLENUM_TYPE words[MAX_LITTLENUMS];
- LITTLENUM_TYPE *wordP;
- char *t;
- char *atof_ieee ();
-
- switch (type)
- {
- case 'f':
- case 'F':
- case 's':
- case 'S':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- prec = 4;
- break;
-
- case 'x':
- case 'X':
- prec = 6;
- break;
-
- case 'p':
- case 'P':
- prec = 6;
- break;
-
- default:
- *sizeP = 0;
- return "Bad call to MD_NTOF()";
- }
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * sizeof (LITTLENUM_TYPE);
- for (wordP = words; prec--;)
- {
- md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- return ""; /* Someone should teach Dean about null pointers */
- }
-
- int
- md_parse_option (argP, cntP, vecP)
- char **argP;
- int *cntP;
- char ***vecP;
-
- {
- if (!strcmp (*argP, "relax"))
- {
- relax = 1;
- **argP =0;
- }
- return 1;
- }
-
- int md_short_jump_size;
-
- void
- tc_Nout_fix_to_chars ()
- {
- printf ("call to tc_Nout_fix_to_chars \n");
- abort ();
- }
-
- void
- md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
- char *ptr;
- long from_Nddr;
- long to_Nddr;
- fragS *frag;
- symbolS *to_symbol;
- {
- as_fatal ("failed sanity check.");
- }
-
- void
- md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
- char *ptr;
- long from_Nddr, to_Nddr;
- fragS *frag;
- symbolS *to_symbol;
- {
- as_fatal ("failed sanity check.");
- }
-
- /*
- called after relaxing, change the frags so they know how big they are
- */
- void
- md_convert_frag (headers, fragP)
- object_headers *headers;
- fragS *fragP;
-
- {
- unsigned char *buffer = (unsigned char *)(fragP->fr_fix + fragP->fr_literal);
- int donerelax = 0;
- int targ_addr = (S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset);
- switch (fragP->fr_subtype)
- {
- case C (COND_JUMP, COND8):
- {
- /* Get the address of the end of the instruction */
- int next_inst = fragP->fr_fix + fragP->fr_address + 2;
-
- int disp = targ_addr - next_inst -2 ;
- disp /= 2;
- md_number_to_chars (buffer + 1, disp, 1);
- fragP->fr_fix += 2;
- fragP->fr_var = 0;
- }
- break;
-
- case C (UNCOND_JUMP, UNCOND12):
- {
- /* Get the address of the end of the instruction */
- int next_inst = fragP->fr_fix + fragP->fr_address + 2;
-
- int t;
- int disp = targ_addr - next_inst -2 ;
-
- disp /= 2;
- t = buffer[0] & 0xf0;
- md_number_to_chars (buffer , disp, 2);
- buffer[0] = (buffer[0] & 0xf) | t;
- fragP->fr_fix += 2;
- fragP->fr_var = 0;
- }
- break;
-
- case C (UNCOND_JUMP, UNCOND32):
- case C (UNCOND_JUMP, UNDEF_WORD_DISP):
- {
- /* A jump wont fit in 12 bits, make code which looks like
- bra foo
- mov.w @(0, PC), r14
- .long disp
- foo: bra @r14
- */
-
- int next_inst =
- fragP->fr_fix + fragP->fr_address + UNCOND32_LENGTH;
-
- int disp = targ_addr - next_inst ;
- int t = buffer[0] & 0x10;
-
- disp /= 2;
-
- buffer[0] = 0xa0; /* branch over move and disp */
- buffer[1] = 3;
- buffer[2] = 0xd0 | JREG; /* Build mov insn */
- buffer[3] = 0x00;
-
- buffer[4] = 0; /* space for 32 bit jump disp */
- buffer[5] = 0;
- buffer[6] = 0;
- buffer[7] = 0;
-
- buffer[10] = 0x40 | JREG; /* Build jmp @JREG */
- buffer[11] = t ? 0xb : 0x2b ;
-
- buffer[12] = 0x20; /* build nop */
- buffer[13] = 0x0b;
-
- /* Make reloc for the long disp */
- fix_new(fragP,
- fragP->fr_fix + 4,
- 4,
- fragP->fr_symbol,
- 0,
- fragP->fr_offset,
- 0,
- R_SH_IMM32);
- fragP->fr_fix += UNCOND32_LENGTH;
- fragP->fr_var = 0;
- donerelax = 1;
-
- }
- break;
-
- case C (COND_JUMP, COND12):
- {
- /* A bcond won't fit, so turn it into a b!cond; bra disp; nop */
- int next_inst =
- fragP->fr_fix + fragP->fr_address + 6;
-
- int disp = targ_addr - next_inst ;
- disp /= 2;
- md_number_to_chars (buffer + 2, disp, 2);
- buffer[0] ^= 0x2; /* Toggle T/F bit */
- buffer[1] = 1; /* branch over jump and nop */
- buffer[2] = (buffer[2] & 0xf) | 0xa0; /* Build jump insn */
- buffer[4] = 0x20; /* Build nop */
- buffer[5] = 0x0b;
- fragP->fr_fix += 6;
- fragP->fr_var = 0;
- donerelax = 1;
- }
- break;
-
- case C (COND_JUMP, COND32):
- case C (COND_JUMP, UNDEF_WORD_DISP):
- {
- /* A bcond won't fit and it won't go into a 12 bit
- displacement either, the code sequence looks like:
- b!cond foop
- mov.w @(n, PC), r14
- jmp @r14
- nop
- .long where
- foop:
- */
-
- int next_inst =
- fragP->fr_fix + fragP->fr_address + COND32_LENGTH;
-
- int disp = targ_addr - next_inst ;
- disp /= 2;
-
- buffer[0] ^= 0x2; /* Toggle T/F bit */
- #define JREG 14
- buffer[1] = 5; /* branch over mov, jump, nop and ptr */
- buffer[2] = 0xd0 | JREG; /* Build mov insn */
- buffer[3] = 0x2;
- buffer[4] = 0x40 | JREG; /* Build jmp @JREG */
- buffer[5] = 0x0b;
- buffer[6] = 0x20; /* build nop */
- buffer[7] = 0x0b;
- buffer[8] = 0; /* space for 32 bit jump disp */
- buffer[9] = 0;
- buffer[10] = 0;
- buffer[11] = 0;
- buffer[12] = 0;
- buffer[13] = 0;
- /* Make reloc for the long disp */
- fix_new(fragP,
- fragP->fr_fix + 8,
- 4,
- fragP->fr_symbol,
- 0,
- fragP->fr_offset,
- 0,
- R_SH_IMM32);
- fragP->fr_fix += COND32_LENGTH;
- fragP->fr_var = 0;
- donerelax = 1;
- }
- break;
-
- default:
- abort ();
- }
-
- if (donerelax && !relax)
- {
- as_bad("Offset doesn't fit at 0x%x, trying to get to 0x%x",
- fragP->fr_address,
- targ_addr);
- }
-
- }
-
- long
- DEFUN (md_section_align, (seg, size),
- segT seg AND
- long size)
- {
- return ((size + (1 << section_alignment[(int) seg]) - 1)
- & (-1 << section_alignment[(int) seg]));
-
- }
-
- void
- md_apply_fix (fixP, val)
- fixS *fixP;
- long val;
- {
- char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
- int addr = fixP->fx_frag->fr_address + fixP->fx_where;
- if (fixP->fx_r_type == 0)
- {
- fixP->fx_r_type = R_SH_IMM32 ;
- }
-
- switch (fixP->fx_r_type)
- {
-
- case R_SH_IMM4:
- *buf = (*buf & 0xf0) | (val & 0xf);
- break;
-
- case R_SH_IMM4BY2:
- *buf = (*buf & 0xf0) | ((val>>1) & 0xf);
- break;
-
- case R_SH_IMM4BY4:
- *buf = (*buf & 0xf0) | ((val>>2) & 0xf);
- break;
-
- case R_SH_IMM8BY2:
- *buf = val >>1;
- break;
-
- case R_SH_IMM8BY4:
- *buf = val >>2;
- break;
-
- case R_SH_IMM8:
- *buf++ = val;
- break;
-
- case R_SH_PCRELIMM8BY4:
- addr &= ~1;
-
- if (val & 0x3)
- as_warn("non aligned displacement at %x\n", addr);
- val -=(addr+4);
- val+=3;
- val /= 4;
- if (val & ~0xff)
- as_warn("pcrel too far at %x\n", addr);
-
- *buf = val ;
- break;
-
- case R_SH_PCRELIMM8BY2:
- addr &= ~1;
- if (val & 0x1)
- as_bad("odd displacement at %x\n", addr);
- val -= (addr+4);
- val++;
- val /= 2;
- if (val & ~0xff)
- as_warn("pcrel too far at %x\n", addr);
- *buf= val;
- break;
-
- case R_SH_IMM32:
- *buf++ = val >>24;
- *buf++ = val >>16;
- *buf++ = val >>8;
- *buf++ = val >>0;
- break;
-
- default:
- abort ();
- }
- }
-
- void
- DEFUN (md_operand, (expressionP), expressionS * expressionP)
- {
- }
-
- int md_long_jump_size;
-
- /*
- called just before address relaxation, return the length
- by which a fragment must grow to reach it's destination
- */
- int
- md_estimate_size_before_relax (fragP, segment_type)
- register fragS *fragP;
- register segT segment_type;
- {
- switch (fragP->fr_subtype)
- {
- case C(UNCOND_JUMP, UNDEF_DISP):
- /* used to be a branch to somewhere which was unknown */
- if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
- {
- fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
- fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length;
- }
- else
- {
- fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP);
- fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length;
- return md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length;
- }
- break;
-
- default:
- abort ();
- case C (COND_JUMP, UNDEF_DISP):
- /* used to be a branch to somewhere which was unknown */
- if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
- {
- /* Got a symbol and it's defined in this segment, become byte
- sized - maybe it will fix up */
- fragP->fr_subtype = C (COND_JUMP, COND8);
- fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
- }
- else
- {
- /* Its got a segment, but its not ours, so it will always be long */
- fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP);
- fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length;
- return md_relax_table[C (COND_JUMP, COND32)].rlx_length;
- }
- break;
- }
- return fragP->fr_var;
- }
-
- /* Put number into target byte order */
-
- void
- md_number_to_chars (ptr, use, nbytes)
- char *ptr;
- long use;
- int nbytes;
- {
- switch (nbytes)
- {
- case 4:
- *ptr++ = (use >> 24) & 0xff;
- case 3:
- *ptr++ = (use >> 16) & 0xff;
- case 2:
- *ptr++ = (use >> 8) & 0xff;
- case 1:
- *ptr++ = (use >> 0) & 0xff;
- break;
- default:
- abort ();
- }
- }
- long
- md_pcrel_from (fixP)
- fixS *fixP;
-
- {
- int gap = fixP->fx_size + fixP->fx_where +
- fixP->fx_frag->fr_address;
- return gap;
- }
-
- void
- tc_coff_symbol_emit_hook ()
- {
- }
-
- short
- tc_coff_fix2rtype (fix_ptr)
- fixS *fix_ptr;
- {
- return fix_ptr->fx_r_type;
- }
-
- void
- tc_reloc_mangle (fix_ptr, intr, base)
- fixS *fix_ptr;
- struct internal_reloc *intr;
- bfd_vma base;
-
- {
- symbolS *symbol_ptr;
-
- symbol_ptr = fix_ptr->fx_addsy;
-
- /* If this relocation is attached to a symbol then it's ok
- to output it */
- if (fix_ptr->fx_r_type == RELOC_32)
- {
- /* cons likes to create reloc32's whatever the size of the reloc..
- */
- switch (fix_ptr->fx_size)
- {
- case 2:
- intr->r_type = R_IMM16;
- break;
- case 1:
- intr->r_type = R_IMM8;
- break;
- default:
- abort ();
- }
- }
- else
- {
- intr->r_type = fix_ptr->fx_r_type;
- }
-
- intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base;
- intr->r_offset = fix_ptr->fx_offset;
-
- /* Turn the segment of the symbol into an offset. */
- if (symbol_ptr)
- {
- symbolS *dot;
-
- dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot;
- if (dot)
- {
- intr->r_offset += S_GET_VALUE (symbol_ptr);
- intr->r_symndx = dot->sy_number;
- }
- else
- {
- intr->r_symndx = symbol_ptr->sy_number;
- }
- }
- else
- {
- intr->r_symndx = -1;
- }
- }
-
- int
- tc_coff_sizemachdep(frag)
- fragS *frag;
- {
- return md_relax_table[frag->fr_subtype].rlx_length;
- }
- /* end of tc-sh.c */
-